/*
 * author: hujingfei914@msn.com
 * date: 2010-10-14
 * description: Load texture files
 */
#include "..\stdafx.h"
#include "Texture.h"
#include <math.h>

bool loadTexture(char *fileName, GLuint &texId)
{
	// DC is used to save bitmap
	HDC			hdcTemp;												
	// Save the temporary bitmap
	HBITMAP		hbmpTemp;			
	// Define IPicture Interface
	IPicture	*pPicture;												
	// The complete path of the picture
	OLECHAR		wszPath[MAX_PATH + 1];
	// The complete path of the picture
	char		szPath[MAX_PATH + 1];
		
	long		lWidth;													
	long		lHeight;												
	long		lWidthPixels;											
	long		lHeightPixels;			

	GLint		glMaxTexDim ;											

	// Get the current directory path
	GetCurrentDirectoryA(MAX_PATH, szPath);		
	// Add '\\'
	strcat(szPath, "\\");	
	// Add the relative path
	strcat(szPath, fileName);
	// Convert to the wide char
	MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, MAX_PATH);

	HRESULT hr = OleLoadPicturePath(wszPath, 0, 0, 0, IID_IPicture, (void**)&pPicture);
	// If failed
	if(FAILED(hr))
	{
		MessageBox (HWND_DESKTOP, _T("Ole loading function failed"), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
		return FALSE;													
	}

    // Creates a memory device context (DC) compatible with the specified device
	hdcTemp = CreateCompatibleDC(GetDC(0));		
	// If failed
	if(!hdcTemp)														
	{
		pPicture->Release();										
		MessageBox (HWND_DESKTOP, _T("Memory DC creating failed"), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
		return FALSE;													
	}

	// Get the maximal supported Texture size
	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);					
	
	pPicture->get_Width(&lWidth);										
	lWidthPixels = MulDiv(lWidth, GetDeviceCaps(hdcTemp, LOGPIXELSX), 2540);
	pPicture->get_Height(&lHeight);										
	lHeightPixels = MulDiv(lHeight, GetDeviceCaps(hdcTemp, LOGPIXELSY), 2540);

	// Adjust the picture to a better condition
	if (lWidthPixels <= glMaxTexDim) {									
		lWidthPixels = 1 << (int) floor(log((double)lWidthPixels) / log(2.0f) + 0.5f ); 
	} else {																
		lWidthPixels = glMaxTexDim;
	}
 
	if (lHeightPixels <= glMaxTexDim) {								
		lHeightPixels = 1 << (int)floor(log((double)lHeightPixels) / log(2.0f) + 0.5f);
	} else	 {														
		lHeightPixels = glMaxTexDim;
	}

	// Build a temporary bitmap
	BITMAPINFO	bi = {0};											
	// Pointer to the bitmap
	DWORD *pBits = 0;												

	// Some initialization
	bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);				
	bi.bmiHeader.biBitCount	 = 32;									
	bi.bmiHeader.biWidth	 = lWidthPixels;							
	bi.bmiHeader.biHeight = lHeightPixels;						
	// RGB 
	bi.bmiHeader.biCompression	= BI_RGB;
	// One bit plane
	bi.bmiHeader.biPlanes = 1;

	// After build a bitmap, we can specify the color and depth, and access the value of each bit
	hbmpTemp = CreateDIBSection(hdcTemp, &bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0);
	
	// If failed
	if(!hbmpTemp)													
	{
		DeleteDC(hdcTemp);												
		pPicture->Release();	
		MessageBox (HWND_DESKTOP, _T("Create DIB failed"), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
		return FALSE;												
	}

	// Selects hbmpTemp into the specified device context (DC) hdcTemp. 
	SelectObject(hdcTemp, hbmpTemp);

	// Draw IPicture on the bitmap
	pPicture->Render(hdcTemp, 0, 0, lWidthPixels, lHeightPixels, 0, lHeight, lWidth, -lHeight, 0);
	
	// Transform the BGR to RGB and set ALPHA to 255
	for(long i = 0; i < lWidthPixels * lHeightPixels; i++)				
	{
		// Get the current pixel
		BYTE* pPixel	= (BYTE*)(&pBits[i]);							
		// Because the first is blue
		BYTE  temp		= pPixel[0];									
		pPixel[0]		= pPixel[2];									
		pPixel[2]		= temp;										
		pPixel[3]		= 255;										
	}

	// Start to create Texture
	glGenTextures(1, &texId);											

	glBindTexture(GL_TEXTURE_2D, texId);				

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	// Generate Texture
	glTexImage2D(GL_TEXTURE_2D, 0, 3, lWidthPixels, lHeightPixels, 0, GL_RGBA, GL_UNSIGNED_BYTE, pBits);

	gluBuild2DMipmaps(GL_TEXTURE_2D, 4, lWidthPixels, lHeightPixels, GL_RGBA, GL_UNSIGNED_BYTE, pBits);

	DeleteObject(hbmpTemp);												
	DeleteDC(hdcTemp);													

	pPicture->Release();												

	return TRUE;
}

// Deprecated...
int num_texture = -1;
int loadBitmap(char *filename) 
{
    int i, j=0; //Index variables
    FILE *l_file; //File pointer
    unsigned char *l_texture; //The pointer to the memory zone in which we will load the texture
     
    // windows.h gives us these types to work with the Bitmap files
    BITMAPFILEHEADER fileheader; 
    BITMAPINFOHEADER infoheader;
    RGBTRIPLE rgb;

    num_texture++; // The counter of the current texture is increased

    if( (l_file = fopen(filename, "rb"))==NULL) return (-1); // Open the file for reading
    
    fread(&fileheader, sizeof(fileheader), 1, l_file); // Read the fileheader
    
    fseek(l_file, sizeof(fileheader), SEEK_SET); // Jump the fileheader
    fread(&infoheader, sizeof(infoheader), 1, l_file); // and read the infoheader

    // Now we need to allocate the memory for our image (width * height * color deep)
    l_texture = (byte *) malloc(infoheader.biWidth * infoheader.biHeight * 4);
    // And fill it with zeros
    memset(l_texture, 0, infoheader.biWidth * infoheader.biHeight * 4);
 
    // At this point we can read every pixel of the image
    for (i=0; i < infoheader.biWidth*infoheader.biHeight; i++)
    {            
            // We load an RGB value from the file
            fread(&rgb, sizeof(rgb), 1, l_file); 

            // And store it
            l_texture[j+0] = rgb.rgbtRed; // Red component
            l_texture[j+1] = rgb.rgbtGreen; // Green component
            l_texture[j+2] = rgb.rgbtBlue; // Blue component
            l_texture[j+3] = 255; // Alpha value
            j += 4; // Go to the next position
    }

    fclose(l_file); // Closes the file stream
    
	
    glBindTexture(GL_TEXTURE_2D, num_texture); // Bind the ID texture specified by the 2nd parameter

    // The next commands sets the texture parameters
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // If the u,v coordinates overflow the range 0,1 the image is repeated
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // The magnification function ("linear" produces better results)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); //The minifying function

    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // We don't combine the color with the original surface color, use only the texture map.

    // Finally we define the 2d texture
    glTexImage2D(GL_TEXTURE_2D, 0, 4, infoheader.biWidth, infoheader.biHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);

    // And create 2d mipmaps for the minifying function
    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, infoheader.biWidth, infoheader.biHeight, GL_RGBA, GL_UNSIGNED_BYTE, l_texture);

    free(l_texture); // Free the memory we used to load the texture

    return (num_texture); // Returns the current texture OpenGL ID
}